package org.jumuning.redis.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.jumuning.redis.jackson.JavaTimeModule;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author jumuning
 * @description 封装Jackson的json工具类，用于代替JSONObject
 */
@Slf4j
public class JacksonUtil {

    public static ObjectMapper objectMapper = new ObjectMapper();

    /**
     * Java对象转JSON字符串
     * @param object 对象
     * @return String
     */
    public static String toJsonString(Object object) {
        try {
            objectMapper.registerModule(new JavaTimeModule());
            return objectMapper.writeValueAsString(object);
        }
        catch (JsonProcessingException e) {
            log.error("The JacksonUtil toJsonString is error : \n", e);
            throw new RuntimeException();
        }
    }

    /**
     * Java对象转JsonNode
     * @param object 对象
     * @return String
     */
    public static JsonNode toJsonNode(String object) {
        try {
            objectMapper.registerModule(new JavaTimeModule());
            return objectMapper.readTree(object);
        }
        catch (JsonProcessingException e) {
            log.error("The JacksonUtil toJsonString is error : \n", e);
            throw new RuntimeException();
        }
    }

    /**
     * Java对象转JSON字符串 - 美化输出
     * @param object 对象
     * @return String
     */
    public static String toJsonStringWithPretty(Object object) {
        try {
            objectMapper.registerModule(new JavaTimeModule());
            return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(object);
        }
        catch (JsonProcessingException e) {
            log.error("The JacksonUtil toJsonString is error : \n", e);
            throw new RuntimeException();
        }
    }

    /**
     * Java对象转byte数组
     * @param object 对象
     * @return byte[]
     */
    public static byte[] toJsonAsBytes(Object object) {
        try {
            objectMapper.registerModule(new JavaTimeModule());
            return objectMapper.writeValueAsBytes(object);
        }
        catch (JsonProcessingException e) {
            log.error("The JacksonUtil toJsonBytes is error : \n", e);
            throw new RuntimeException();
        }
    }

    /**
     * JSON字符串转对象
     * @param json json字符串
     * @param clazz 转化泛型对象
     * @param <T> 泛型对象
     * @return <T>
     */
    public static <T> T parseObject(String json, Class<T> clazz) {
        try {
            objectMapper.registerModule(new JavaTimeModule());
            return objectMapper.readValue(json, clazz);
        }
        catch (Exception e) {
            log.error("The JacksonUtil parseObject is error, json str is {}, class name is {} \n", json,
                    clazz.getName(), e);
            throw new RuntimeException();
        }
    }

    /**
     * JSON字符串转List集合
     * @param json json字符串
     * @param elementClasses 元素类
     * @param <T> 泛型对象
     * @return List<T>
     */
    @SafeVarargs
    public static <T> List<T> parseList(String json, Class<T>... elementClasses) {
        try {
            objectMapper.registerModule(new JavaTimeModule());
            return objectMapper.readValue(json, getCollectionType(objectMapper, List.class, elementClasses));
        }
        catch (Exception e) {
            log.error("The JacksonUtil parseList is error, json str is {}, element class name is {} \n", json,
                    elementClasses.getClass().getName(), e);
            throw new RuntimeException();
        }
    }

    /**
     * JSON字符串转Set集合
     * @param json json字符串
     * @param elementClasses 元素类
     * @param <T> 泛型对象
     * @return Set<T>
     */
    @SafeVarargs
    public static <T> Set<T> parseSet(String json, Class<T>... elementClasses) {
        try {
            objectMapper.registerModule(new JavaTimeModule());
            return objectMapper.readValue(json, getCollectionType(objectMapper, Set.class, elementClasses));
        }
        catch (Exception e) {
            log.error("The JacksonUtil parseSet is error, json str is {}, element class name is {} \n", json,
                    elementClasses.getClass().getName(), e);
            throw new RuntimeException();
        }
    }

    /**
     * JSON字符串转Collection集合
     * @param json json字符串
     * @param elementClasses 元素类
     * @param <T> 泛型对象
     * @return Collection<T>
     */
    @SafeVarargs
    public static <T> Collection<T> parseCollection(String json, Class<T>... elementClasses) {
        try {
            objectMapper.registerModule(new JavaTimeModule());
            return objectMapper.readValue(json, getCollectionType(objectMapper, Collection.class, elementClasses));
        }
        catch (Exception e) {
            log.error("The JacksonUtil parseCollection is error, json str is {}, element class name is {} \n", json,
                    elementClasses.getClass().getName(), e);
            throw new RuntimeException();
        }
    }

    /**
     * JSON字符串转Map集合
     * @param json json字符串
     * @param <T> 泛型对象
     * @return Map<String,Object></><T>
     */
    public static <T> Map<String, Object> parseMap(T json, Class<T> valueType) {
        try {
            objectMapper.registerModule(new JavaTimeModule());
            return objectMapper.readValue(String.valueOf(json),
                    objectMapper.getTypeFactory().constructMapType(Map.class, String.class, Object.class));
        }
        catch (Exception e) {
            log.error("The JacksonUtil parseMap is error, json str is {}, element class name is {} \n", json,
                    valueType.getName(), e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取泛型的Collection Type
     * @param collectionClass 泛型的Collection
     * @param elementClasses 元素类
     * @return JavaType Java类型
     */
    public static JavaType getCollectionType(ObjectMapper mapper, Class<?> collectionClass,
                                             Class<?>... elementClasses) {
        return mapper.getTypeFactory().constructParametricType(collectionClass, elementClasses);
    }

    /**
     * 判断字符串是否为有效的JSON格式
     * @param json 待判断的字符串
     * @return 如果是有效的JSON格式返回true，否则返回false
     */
    public static boolean isTypeJSON(String json) {
        try {
            objectMapper.registerModule(new JavaTimeModule());
            objectMapper.readTree(json);
            return true;
        }
        catch (JsonProcessingException e) {
            return false;
        }
    }

}
